//=============================================================================
///	String
/**

Functions:
	string-length
	string-ref
	string-copy
	string-append

*/
//=============================================================================

#include "mstring.h"
#include "sstring.h"
#include "sexp.h"
#include "ssym.h"
#include "senv.h"
#include <string.h>

static const char ERR_OUT_OF_RANGE[] = "out of range: ~a for ~s";


//=============================================================================
// subr

static SExp subr_string_length(int narg, SExp args[]) {
	SExp s = type_check(args[0], tString);
	return fixnum2s(s.ptr->string.len);
}

static SExp subr_string_ref(int narg, SExp args[]) {
	SExp s = type_check(args[0], tString);
	SExp i = type_check(args[1], tFixnum);
	const char* str = s.ptr->string.str;
	int idx = s2fixnum(i);
	if (0 <= idx && idx < s.ptr->string.len) {
		return char2s(str[idx]);
	} else {
		return error(ERR_OUT_OF_RANGE, i, s);
	}
}

static SExp subr_string_copy(int narg, SExp args[]) {
	SExp s = type_check(args[0], tString);
	int len = s.ptr->string.len;
	const char* str = s.ptr->string.str;
	int start = 0, end = len;
	if (narg >= 2) {
		SExp ss = type_check(args[1], tFixnum);
		start = s2fixnum(ss);
	}
	if (narg >= 3) {
		SExp se = type_check(args[2], tFixnum);
		end = s2fixnum(se);
	}
	if (start < 0 || len < start) {
		return error(ERR_OUT_OF_RANGE, fixnum2s(start), s);
	}
	if (start > end) {
		return error(ERR_OUT_OF_RANGE, fixnum2s(start), s);
	}
	return gen_str(&s.ptr->string.str[start], end - start);
}

static SExp subr_string_append(int narg, SExp args[]) {
	if (narg == 0) {
		return gen_str("", -1);
	} else {
		SExp s = type_check(args[0], tString);
		int i;
		for (i=1; i<narg; ++i) {
			SExp a = type_check(args[i], tString);
			s = concat(s, a);
		}
		return s;
	}
}


//=============================================================================

void define_string_module(void) {
	struct {
		const char* name;
		SubrType cfunc;
		int minargnum, maxargnum;
	} subr_tbl[] = {
		{	"string-length",	subr_string_length,		1,	1,	},
		{	"string-ref",		subr_string_ref,		2,	2,	},
		{	"string-copy",		subr_string_copy,		1,	3,	},
		{	"string-append",	subr_string_append,		0,	-1,	},
	};
	int i;
	for (i=0; i<sizeof(subr_tbl)/sizeof(*subr_tbl); ++i) {
		SExp subr = gen_subr(subr_tbl[i].cfunc, subr_tbl[i].name, subr_tbl[i].minargnum, subr_tbl[i].maxargnum);
		SExp sym = intern(subr_tbl[i].name);
		setq(sym, subr);
	}
}

